Added simple example script for running multiple run control apps - #333
Added simple example script for running multiple run control apps#333bieryAtFnal wants to merge 7 commits into
Conversation
… unified shell as separate processes.
…iproc_runcontrol_script
…iproc_runcontrol_script
emmuhamm
left a comment
There was a problem hiding this comment.
Okay this is pretty epic, thanks Kurt!
I was able to install and run this just fine locally, being able to spawn this which is basically a 'wrapper' for multiple apps which is very very cool. Everything mostly works as expected.
I've left a few minor comments, but none I would consider blockers. I would prefer this to go in rather than waiting some time to make this perfect since base functionality works and this can always be iterated upon later.
Anyways consider this a soft approval from my side. I can approve this with the button if the comments have been addressed.
| interactive_cmds = [ | ||
| ["pm", "drunc-process-manager", "ssh-standalone", str(pm_port)], # Launch Interactive Python Instance 1 | ||
| ["pmshell", "drunc-process-manager-shell", f"grpc://localhost:{pm_port}"], # Launch Interactive Python Instance 2 | ||
| ["drunc", "drunc-unified-shell", f"grpc://localhost:{pm_port}", "config/daqsystemtest/example-configs.data.xml", "local-1x1-config", "biery-local-test"] # Launch Interactive Python Instance 3 | ||
| ] |
There was a problem hiding this comment.
Is the purpose of this script for a test/demonstration of the PMaaS functionality or are people expected to use this more generally / in a wider use case?
If its the latter, then maybe people might want to change these lines to fit their needs? I would suggest the following:
- The easiest might be a comment / some docs here that says 'please change this to change what set of applications you would like to run'. In these comments, it would have to be clear that the first element of this list is the 'alias' of the application and the rest are just the usual application setups
- Something harder, possibly not worth it, is to open this up as an runtime argument. I'm ambivalent / semi against this idea though
| if "drunc" in target: | ||
| proc.stdin.write(("echo '*** COMMAND HAS COMPLETED ***'\n").encode()) | ||
| await proc.stdin.drain() | ||
| #print(f"[System] Sent to {target}: echo '*** COMMAND HAS COMPLETED ***'") |
There was a problem hiding this comment.
Here and a couple of others: Some stray comments that should be deleted before merge into develop
| @@ -0,0 +1,140 @@ | |||
| #!/bin/env python3 | |||
There was a problem hiding this comment.
I thikn the top of this file is missing a bit of documentation. People should know how to run this and what this script does, as well as a brief description of how to interact with the shells. (and then maybe add a todo to link these to the PMaaS docs when we eventually make them >.<)
| print("*** Type 'exit' to quit everything.") | ||
| print() | ||
|
|
||
| # 3. Handle interactive user input from the main terminal |
There was a problem hiding this comment.
One thing I noticed is that arrow keys don't work. Makes a bit hard to submit the previous commands.
I dont think this is a blocker for this merge tho. It would be nice if it can make it but if its too difficult I'm happy for this to be deferred
| if ":" in command_text: | ||
| target, msg = command_text.split(":", 1) | ||
| target = target.strip() | ||
|
|
||
| if target in processes: | ||
| proc = processes[target] | ||
| if proc.returncode is None: # Check if still running | ||
| cmd_start_time = time.time() | ||
| proc.stdin.write((msg + "\n").encode()) | ||
| await proc.stdin.drain() | ||
| print(f"[System] Sent to {target}: {msg}") | ||
| if "drunc" in target: | ||
| proc.stdin.write(("echo '*** COMMAND HAS COMPLETED ***'\n").encode()) | ||
| await proc.stdin.drain() | ||
| #print(f"[System] Sent to {target}: echo '*** COMMAND HAS COMPLETED ***'") | ||
| await command_completion_event.wait() | ||
| command_completion_event.clear() | ||
| else: | ||
| now = time.time() | ||
| #print(f"{cmd_start_time} {last_msg_time} {now}", flush=True) | ||
| while True: | ||
| if last_msg_time <= cmd_start_time: | ||
| if now - cmd_start_time > 5: | ||
| break | ||
| else: | ||
| if now - last_msg_time >= 5: | ||
| break | ||
| #print(f"{cmd_start_time} {last_msg_time} {now}", flush=True) | ||
| await asyncio.sleep(0.25) | ||
| now = time.time() | ||
| #print(f"{cmd_start_time} {last_msg_time} {now}", flush=True) | ||
| else: | ||
| print(f"[System] Error: {target} has already exited.") | ||
| else: | ||
| print(f"[System] Error: Process '{target}' not found.") | ||
| else: | ||
| print("[System] Invalid format. Use: <process_name>:<command>") |
There was a problem hiding this comment.
Quite a nested block of code. I prefer if its inverted to flatten them:
| if ":" in command_text: | |
| target, msg = command_text.split(":", 1) | |
| target = target.strip() | |
| if target in processes: | |
| proc = processes[target] | |
| if proc.returncode is None: # Check if still running | |
| cmd_start_time = time.time() | |
| proc.stdin.write((msg + "\n").encode()) | |
| await proc.stdin.drain() | |
| print(f"[System] Sent to {target}: {msg}") | |
| if "drunc" in target: | |
| proc.stdin.write(("echo '*** COMMAND HAS COMPLETED ***'\n").encode()) | |
| await proc.stdin.drain() | |
| #print(f"[System] Sent to {target}: echo '*** COMMAND HAS COMPLETED ***'") | |
| await command_completion_event.wait() | |
| command_completion_event.clear() | |
| else: | |
| now = time.time() | |
| #print(f"{cmd_start_time} {last_msg_time} {now}", flush=True) | |
| while True: | |
| if last_msg_time <= cmd_start_time: | |
| if now - cmd_start_time > 5: | |
| break | |
| else: | |
| if now - last_msg_time >= 5: | |
| break | |
| #print(f"{cmd_start_time} {last_msg_time} {now}", flush=True) | |
| await asyncio.sleep(0.25) | |
| now = time.time() | |
| #print(f"{cmd_start_time} {last_msg_time} {now}", flush=True) | |
| else: | |
| print(f"[System] Error: {target} has already exited.") | |
| else: | |
| print(f"[System] Error: Process '{target}' not found.") | |
| else: | |
| print("[System] Invalid format. Use: <process_name>:<command>") | |
| if ":" not in command_text: | |
| print("[System] Invalid format. Use: <process_name>:<command>") | |
| continue | |
| target, msg = command_text.split(":", 1) | |
| target = target.strip() | |
| if target not in processes: | |
| print(f"[System] Error: Process '{target}' not found.") | |
| continue | |
| proc = processes[target] | |
| if proc.returncode is not None: | |
| print(f"[System] Error: {target} has already exited.") | |
| continue | |
| cmd_start_time = time.time() | |
| proc.stdin.write((msg + "\n").encode()) | |
| await proc.stdin.drain() | |
| print(f"[System] Sent to {target}: {msg}") | |
| if "drunc" in target: | |
| proc.stdin.write(("echo '*** COMMAND HAS COMPLETED ***'\n").encode()) | |
| await proc.stdin.drain() | |
| await command_completion_event.wait() | |
| command_completion_event.clear() | |
| continue | |
| now = time.time() | |
| while True: | |
| if last_msg_time <= cmd_start_time and now - cmd_start_time > 5: | |
| break | |
| if last_msg_time > cmd_start_time and now - last_msg_time >= 5: | |
| break | |
| await asyncio.sleep(0.25) | |
| now = time.time() |
Comments on each if statement as necessary too if theyre not clear enough
…iproc_runcontrol_script
|
Thanks, @emmuhamm, for taking a look. |
Description
When I was starting to think about how we might add support for multiple, user-specified applications to be run as part of our integration tests, I ran some Google searches that produced sample python code that was very helpful.
I modified that sample code to start
drunc-unified-shell,drunc-process-manager, anddrunc-process-manager-shellprocesses.The end result was so helpful that I wanted to capture the result for later use.
This PR adds this script to this repo.
The script can by run by typing
multiprocess_runcontrol_driver.pyafter including this branch in your software area and re-building the code in that software area.Once the script has been started, commands can be sent to one of the three processes by pre-pending the process nickname to the command (with a colon separator). For example,
drunc:ps.Typing
exit(with no process prefix) will exit the script.Type of change